using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using YTS.Test;
using YTS.Tools;

namespace Test.ConsoleProgram.Algorithm.Work
{
    [TestDescription("工作逻辑: 解析填充题目信息")]
    public class Test_SujectBankExaminationQuestion : AbsBaseTestItem
    {
        private readonly ITestOutput output;

        public Test_SujectBankExaminationQuestion(ITestOutput output)
        {
            this.output = output;
        }

        public override void OnTest()
        {
            OnTest1();
            OnTest2();
        }
        public void OnTest1()
        {
            var help = new SujectBankExaminationQuestionHelper();

            Assert.TestExe(help.ToNormalOptions,
                new Ubcj_SujectBank()
                {
                    IsMatrix = false,
                    SubjectTitle = "是否是题目1",
                    OptionList = "[1,2]",
                    OptionContent = "",
                    OptionScore = "[10, 15]",
                    OptionNumber = 2,
                    SubjectGrade = 25,
                },
                equalsMethod: (p1, p2) => p1.TestEqualsJSON(p2),
                new List<NormalOption>()
                {
                    new NormalOption() { Ordinal = 1, Content = "", Score = 10 },
                    new NormalOption() { Ordinal = 2, Content = "", Score = 15 },
                });

            Assert.TestExe(help.ToNormalOptions,
                new Ubcj_SujectBank()
                {
                    IsMatrix = false,
                    SubjectTitle = "是否是题目1",
                    OptionList = "[1,2]",
                    OptionContent = "[\"是\", \"否\"]",
                    OptionScore = "[10, 15]",
                    OptionNumber = 2,
                    SubjectGrade = 25,
                },
                equalsMethod: (p1, p2) => p1.TestEqualsJSON(p2),
                new List<NormalOption>()
                {
                    new NormalOption() { Ordinal = 1, Content = "是", Score = 10 },
                    new NormalOption() { Ordinal = 2, Content = "否", Score = 15 },
                });

            Assert.TestExe(help.ToNormalOptions,
                new Ubcj_SujectBank()
                {
                    IsMatrix = false,
                    SubjectTitle = "饮酒后驾驶机动车一次记几分？",
                    OptionList = "[1,2,3,4]",
                    OptionContent = "[\"2分\", \"3分\", \"6分\", \"12分\"]",
                    OptionScore = "[10, 15, 10, 20]",
                    OptionNumber = 4,
                    SubjectGrade = 55,
                },
                equalsMethod: (p1, p2) => p1.TestEqualsJSON(p2),
                new List<NormalOption>()
                {
                    new NormalOption() { Ordinal = 1, Content = "2分", Score = 10 },
                    new NormalOption() { Ordinal = 2, Content = "3分", Score = 15 },
                    new NormalOption() { Ordinal = 3, Content = "6分", Score = 10 },
                    new NormalOption() { Ordinal = 4, Content = "12分", Score = 20 },
                });

            Assert.TestExe(help.ToMatrixOptions,
                new Ubcj_SujectBank()
                {
                    IsMatrix = true,
                    SubjectTitle = "城市公路最高车速?",
                    OptionList = "[[1,3],[2,4]]",
                    OptionContent = "[[\"50公里每小时\",\"70公里每小时\"],[\"30公里每小时\",\"40公里每小时\"]]",
                    OptionScore = "[[10,15],[20,10]]",
                    OptionNumber = 4,
                    SubjectGrade = 55,
                    Matrix_XContent = "[\"城市\",\"公路\"]",
                    Matrix_YContent = "[\"含有中心线\",\"不含中心线\"]",
                    MatrixIsSingle = false,
                },
                equalsMethod: (p1, p2) => p1.TestEqualsJSON(p2),
                new MatrixOptions()
                {
                    SeqX = new string[] { "城市", "公路" },
                    SeqY = new string[] { "含有中心线", "不含中心线" },
                    MatrixTable = new List<IList<NormalOption>>()
                    {
                        new List<NormalOption>()
                        {
                            new NormalOption() { Ordinal = 1, Content = "50公里每小时", Score = 10 },
                            new NormalOption() { Ordinal = 3, Content = "70公里每小时", Score = 15 },
                        },
                        new List<NormalOption>()
                        {
                            new NormalOption() { Ordinal = 2, Content = "30公里每小时", Score = 20 },
                            new NormalOption() { Ordinal = 4, Content = "40公里每小时", Score = 10 },
                        },
                    },
                });

            Assert.TestExe(help.ToMatrixOptions,
                new Ubcj_SujectBank()
                {
                    IsMatrix = true,
                    SubjectTitle = "城市公路最高车速二?",
                    OptionList = "",
                    OptionContent = "[[\"50公里每小时\",\"70公里每小时\",\"120公里每小时\"],[\"30公里每小时\",\"40公里每小时\",\"0公里每小时\"]]",
                    OptionScore = "",
                    OptionNumber = 6,
                    SubjectGrade = 0,
                    Matrix_XContent = "[\"城市\",\"公路\",\"高速\"]",
                    Matrix_YContent = "[\"含有中心线\",\"不含中心线\"]",
                    MatrixIsSingle = false,
                },
                equalsMethod: (p1, p2) => p1.TestEqualsJSON(p2),
                new MatrixOptions()
                {
                    SeqX = new string[] { "城市", "公路", "高速" },
                    SeqY = new string[] { "含有中心线", "不含中心线" },
                    MatrixTable = new List<IList<NormalOption>>()
                    {
                        new List<NormalOption>()
                        {
                            new NormalOption() { Ordinal = 0, Content = "50公里每小时", Score = 0 },
                            new NormalOption() { Ordinal = 0, Content = "70公里每小时", Score = 0 },
                            new NormalOption() { Ordinal = 0, Content = "120公里每小时", Score = 0 },
                        },
                        new List<NormalOption>()
                        {
                            new NormalOption() { Ordinal = 0, Content = "30公里每小时", Score = 0 },
                            new NormalOption() { Ordinal = 0, Content = "40公里每小时", Score = 0 },
                            new NormalOption() { Ordinal = 0, Content = "0公里每小时", Score = 0 },
                        },
                    },
                });
        }
        public void OnTest2()
        {
            var help = new SujectBankExaminationQuestionHelper();

            Test_NormatOptionsList(help, new List<NormalOption>()
            {
                new NormalOption() { Ordinal = 1, Content = "", Score = 10 },
                new NormalOption() { Ordinal = 2, Content = "", Score = 15 },
            });
            Test_NormatOptionsList(help, new List<NormalOption>()
            {
                new NormalOption() { Ordinal = 1, Content = "是", Score = 10 },
                new NormalOption() { Ordinal = 2, Content = "否", Score = 15 },
            });
            Test_NormatOptionsList(help, new List<NormalOption>()
            {
                new NormalOption() { Ordinal = 1, Content = "2分", Score = 10 },
                new NormalOption() { Ordinal = 2, Content = "3分", Score = 15 },
                new NormalOption() { Ordinal = 3, Content = "6分", Score = 10 },
                new NormalOption() { Ordinal = 4, Content = "12分", Score = 20 },
            });

            Test_MatrixOptions(help, new MatrixOptions()
            {
                SeqX = new string[] { "城市", "公路" },
                SeqY = new string[] { "含有中心线", "不含中心线" },
                MatrixTable = new List<IList<NormalOption>>()
                {
                    new List<NormalOption>()
                    {
                        new NormalOption() { Ordinal = 1, Content = "50公里每小时", Score = 10 },
                        new NormalOption() { Ordinal = 3, Content = "70公里每小时", Score = 15 },
                    },
                    new List<NormalOption>()
                    {
                        new NormalOption() { Ordinal = 2, Content = "30公里每小时", Score = 20 },
                        new NormalOption() { Ordinal = 4, Content = "40公里每小时", Score = 10 },
                    },
                },
            });
            Test_MatrixOptions(help, new MatrixOptions()
            {
                SeqX = new string[] { "城市", "公路" },
                SeqY = new string[] { "含有中心线", "不含中心线" },
                MatrixTable = new List<IList<NormalOption>>()
                {
                    new List<NormalOption>()
                    {
                        new NormalOption() { Ordinal = 1, Content = "50公里每小时", Score = 10 },
                        new NormalOption() { Ordinal = 3, Content = "70公里每小时", Score = 15 },
                    },
                    new List<NormalOption>()
                    {
                        new NormalOption() { Ordinal = 2, Content = "30公里每小时", Score = 20 },
                        new NormalOption() { Ordinal = 4, Content = "40公里每小时", Score = 10 },
                    },
                },
            });
            Test_MatrixOptions(help, new MatrixOptions()
            {
                SeqX = new string[] { "城市", "公路", "高速" },
                SeqY = new string[] { "含有中心线", "不含中心线" },
                MatrixTable = new List<IList<NormalOption>>()
                {
                    new List<NormalOption>()
                    {
                        new NormalOption() { Ordinal = 0, Content = "50公里每小时", Score = 0 },
                        new NormalOption() { Ordinal = 0, Content = "70公里每小时", Score = 0 },
                        new NormalOption() { Ordinal = 0, Content = "120公里每小时", Score = 0 },
                    },
                    new List<NormalOption>()
                    {
                        new NormalOption() { Ordinal = 0, Content = "30公里每小时", Score = 0 },
                        new NormalOption() { Ordinal = 0, Content = "40公里每小时", Score = 0 },
                        new NormalOption() { Ordinal = 0, Content = "0公里每小时", Score = 0 },
                    },
                },
            });
        }

        private void Test_NormatOptionsList(SujectBankExaminationQuestionHelper help, IList<NormalOption> list)
        {
            var model = new Ubcj_SujectBank();
            model = help.FillModel(model, list);
            Assert.TestExe(help.ToNormalOptions, model, list);
        }
        private void Test_MatrixOptions(SujectBankExaminationQuestionHelper help, MatrixOptions matrix)
        {
            var model = new Ubcj_SujectBank();
            model = help.FillModel(model, matrix);

            // output.WriteLine(string.Empty);
            // output.WriteLineError(JsonConvert.SerializeObject(matrix));
            // output.WriteLineWarning(JsonConvert.SerializeObject(model));
            // output.WriteLine(string.Empty);

            Assert.TestExe(help.ToMatrixOptions, model, matrix);
        }

        public class MatrixOptions
        {
            public IList<string> SeqX { get; set; }
            public IList<string> SeqY { get; set; }
            public IList<IList<NormalOption>> MatrixTable { get; set; }
        }
        public class NormalOption
        {
            public int? Ordinal { get; set; }
            public string Content { get; set; }
            public int? Score { get; set; }
        }
        public partial class Ubcj_SujectBank
        {
            public int Id { get; set; }
            public string SubjectTypeID { get; set; }
            public string SubjectTitle { get; set; }
            public Nullable<int> OptionNumber { get; set; }
            public string OptionList { get; set; }
            public string OptionContent { get; set; }
            public string OptionScore { get; set; }
            public Nullable<bool> IsMatrix { get; set; }
            public string Matrix_XContent { get; set; }
            public string Matrix_YContent { get; set; }
            public Nullable<bool> MatrixIsSingle { get; set; }
            public Nullable<System.DateTime> AddTime { get; set; }
            public Nullable<long> AddUserID { get; set; }
            public Nullable<int> SubjectGrade { get; set; }
            public Nullable<decimal> SubjectStarts { get; set; }
        }
        /// <summary>
        /// 问卷题库 - 题目相关解析帮助类
        /// </summary>
        public class SujectBankExaminationQuestionHelper
        {
            public SujectBankExaminationQuestionHelper()
            {
            }

            public IList<NormalOption> ToNormalOptions(Ubcj_SujectBank model)
            {
                if (model.IsMatrix ?? false)
                {
                    return new NormalOption[] { };
                }
                model.OptionList = model.OptionList ?? string.Empty;
                model.OptionContent = model.OptionContent ?? string.Empty;
                model.OptionScore = model.OptionScore ?? string.Empty;
                var Ordinals = JsonConvert.DeserializeObject<int?[]>(model.OptionList)
                    ?? new int?[] { };
                var Contents = JsonConvert.DeserializeObject<string[]>(model.OptionContent)
                    ?? new string[] { };
                var Scores = JsonConvert.DeserializeObject<int?[]>(model.OptionScore)
                    ?? new int?[] { };
                var nMax = Math.Max(Math.Max(Ordinals.Length, Contents.Length), Scores.Length);
                var result = new NormalOption[nMax];
                for (int i = 0; i < nMax; i++)
                {
                    result[i] = new NormalOption()
                    {
                        Ordinal = Ordinals.FindIndex(i, 0),
                        Content = Contents.FindIndex(i, string.Empty),
                        Score = Scores.FindIndex(i, 0),
                    };
                }
                return result;
            }

            public MatrixOptions ToMatrixOptions(Ubcj_SujectBank model)
            {
                if (!(model.IsMatrix ?? false))
                {
                    return null;
                }
                model.OptionList = model.OptionList ?? string.Empty;
                model.OptionContent = model.OptionContent ?? string.Empty;
                model.OptionScore = model.OptionScore ?? string.Empty;
                model.Matrix_XContent = model.Matrix_XContent ?? string.Empty;
                model.Matrix_YContent = model.Matrix_YContent ?? string.Empty;

                var Ordinals = JsonConvert.DeserializeObject<IList<IList<int?>>>(model.OptionList)
                    ?? new List<IList<int?>>();
                var Contents = JsonConvert.DeserializeObject<IList<IList<string>>>(model.OptionContent)
                    ?? new List<IList<string>>();
                var Scores = JsonConvert.DeserializeObject<IList<IList<int?>>>(model.OptionScore)
                    ?? new List<IList<int?>>();
                var SeqX = JsonConvert.DeserializeObject<string[]>(model.Matrix_XContent)
                    ?? new string[] { };
                var SeqY = JsonConvert.DeserializeObject<string[]>(model.Matrix_YContent)
                    ?? new string[] { };
                var matrix = new MatrixOptions();

                var list = new List<IList<NormalOption>>();
                for (int y = 0; y < SeqY.Length; y++)
                {
                    var yLine = new List<NormalOption>();
                    for (int x = 0; x < SeqX.Length; x++)
                    {
                        yLine.Add(new NormalOption()
                        {
                            Ordinal = Ordinals.FindIndex(y, null).FindIndex(x, 0),
                            Content = Contents.FindIndex(y, null).FindIndex(x, string.Empty),
                            Score = Scores.FindIndex(y, null).FindIndex(x, 0),
                        });
                    }
                    list.Add(yLine);
                }
                matrix.MatrixTable = list;
                matrix.SeqX = SeqX;
                matrix.SeqY = SeqY;
                return matrix;
            }

            public Ubcj_SujectBank FillModel(Ubcj_SujectBank model, IList<NormalOption> options)
            {
                if (options == null || options.Count <= 0)
                {
                    model.OptionNumber = 0;
                    model.SubjectGrade = 0;
                    model.IsMatrix = false;
                    model.MatrixIsSingle = model.MatrixIsSingle ?? true;
                    model.SubjectStarts = model.SubjectStarts ?? 1;
                    return model;
                }

                model.OptionNumber = options.Count;

                int SubjectGrade = 0;
                model.OptionList = JsonConvert.SerializeObject(options
                    .Select(b => b.Ordinal ?? 0).ToArray());
                model.OptionContent = JsonConvert.SerializeObject(options
                    .Select(b => b.Content ?? string.Empty).ToArray());
                model.OptionScore = JsonConvert.SerializeObject(options
                    .Select(b =>
                    {
                        var value = b.Score ?? 0;
                        SubjectGrade += value;
                        return value;
                    }).ToArray());
                model.SubjectGrade = SubjectGrade;

                model.IsMatrix = false;
                model.MatrixIsSingle = model.MatrixIsSingle ?? true;
                model.SubjectStarts = model.SubjectStarts ?? 1;
                return model;
            }

            public Ubcj_SujectBank FillModel(Ubcj_SujectBank model, MatrixOptions matrix)
            {
                if (matrix == null)
                {
                    model.OptionNumber = 0;
                    model.SubjectGrade = 0;
                    model.IsMatrix = true;
                    model.MatrixIsSingle = model.MatrixIsSingle ?? true;
                    model.SubjectStarts = model.SubjectStarts ?? 1;
                    return model;
                }
                matrix.SeqX = matrix.SeqX ?? new List<string>();
                matrix.SeqY = matrix.SeqY ?? new List<string>();
                matrix.MatrixTable = matrix.MatrixTable ?? new List<IList<NormalOption>>();

                model.IsMatrix = true;
                model.MatrixIsSingle = model.MatrixIsSingle ?? true;
                model.Matrix_XContent = JsonConvert.SerializeObject(matrix.SeqX);
                model.Matrix_YContent = JsonConvert.SerializeObject(matrix.SeqY);
                model.OptionNumber = matrix.MatrixTable.Sum(b => (b?.Count()) ?? 0);

                int SubjectGrade = 0;
                model.OptionList = JsonConvert.SerializeObject(matrix.MatrixTable
                    .Select(b => b?.Select(c => c?.Ordinal ?? 0)));
                model.OptionContent = JsonConvert.SerializeObject(matrix.MatrixTable
                    .Select(b => b?.Select(c => c?.Content ?? string.Empty)));
                model.OptionScore = JsonConvert.SerializeObject(matrix.MatrixTable
                    .Select(b => b?.Select(c =>
                    {
                        var value = c?.Score ?? 0;
                        SubjectGrade += value;
                        return value;
                    })));
                model.SubjectGrade = SubjectGrade;

                model.SubjectStarts = model.SubjectStarts ?? 1;
                return model;
            }
        }
    }
}
